﻿using System.Diagnostics;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using KinonekoSoftware.ArkSpark.Core;
using KinonekoSoftware.ArkSpark.Core.Messages;
using KinonekoSoftware.ArkSpark.Documents.Primitives;
using KinonekoSoftware.ArkSpark.Runtimes;
using KinonekoSoftware.Extensions.Collections;
using KinonekoSoftware.Foundation;
using KinonekoSoftware.Foundation.Styles;
using KinonekoSoftware.Foundation.UI.Controls;
using KinonekoSoftware.Foundation.UI.Controls.Selectors;
using KinonekoSoftware.Foundation.UI.Media;
using KinonekoSoftware.Foundation.UI.Windows.Helpers;

namespace KinonekoSoftware.ArkSpark.Controls
{
    /// <summary>
    /// <see cref="DocumentEditorItem"/> 类型表示一个专门承载文档内容的元素，用于重写 <see cref="ListBoxItem"/> 的逻辑。
    /// </summary>
    public sealed class DocumentEditorItem : ForestListBoxItem
    {
        private WeakReference<DocumentEditor> _asTextEditorReference;

        public static readonly DependencyProperty IsSelectableProperty = DependencyProperty.Register(
                                                                                                     nameof(IsSelectable),
                                                                                                     typeof(bool),
                                                                                                     typeof(DocumentEditorItem),
                                                                                                     new PropertyMetadata(Boxing.False));

        public static readonly Pen DefaultPen = new Pen(new SolidColorBrush(Colors.Gray), 2);
        public static readonly Pen DefaultDashPen = new Pen(new SolidColorBrush(Colors.Gray), 2)
        {
            DashStyle = DashStyles.Dot,
        };
        public static readonly Pen MouseOverPen = new Pen(MediaFactory.ToSolidColorBrush(BrushKey.HighlightB5), 2);
        public static readonly Pen SelectedPen = new Pen(MediaFactory.ToSolidColorBrush(BrushKey.HighlightB3), 2);
        public static readonly Pen MouseOverDashPen = new Pen(MediaFactory.ToSolidColorBrush(BrushKey.HighlightB3), 2)
        {
            DashStyle = DashStyles.Dash,
        };


        public DocumentEditorItem()
        {
            DataContextChanged += OnDataContextChanged;
        }

        private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            IsSelectable = DataContext is IArkSparkModel { IsSelectable: true };
        }

        private void SendMessage(IArkSparkModel iArkSparkModel, DocumentEditor editor)
        {
            //
            // 设置选择的元素
            editor.MessageBus?.OnNext(new NewSelectionEventArgs
            {
                EditingItem = iArkSparkModel,
            });

            //
            // 设置编辑状态。
            if (iArkSparkModel is IArkSparkRuntimeModel iArkSparkRTM)
            {
                iArkSparkRTM.IsEdit = IsSelected;
            }
        }

        protected override void OnMouseEnter(MouseEventArgs e)
        {
            if (!IsSelected)
            {
                InvalidateVisual();
            }
            
            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            if (!IsSelected)
            {
                InvalidateVisual();
            }
            
            base.OnMouseLeave(e);
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            ControlHelper.DrawBackground(this, drawingContext);

            if (IsSelected)
            {
                drawingContext.DrawLine(SelectedPen, new Point(4, 4), new Point(4, ActualHeight));
            }
            else if (IsMouseOver)
            {
                drawingContext.DrawLine(MouseOverPen, new Point(4, 4), new Point(4, ActualHeight));
            }
            else
            {
                drawingContext.DrawLine(DefaultDashPen, new Point(4, 4), new Point(4, ActualHeight));
            }

            base.OnRender(drawingContext);
        }

        protected override void OnSelected(RoutedEventArgs e)
        {
            var editor = TextEditor;

            if (DataContext is not IArkSparkModel iArkSparkModel)
            {
                base.OnSelected(e);
                return;
            }



            if (editor is null)
            {
                base.OnSelected(e);
                return;
            }

            if (iArkSparkModel is DocumentElementPresenter deP)
            {
                deP.IsEdit = true;
            }

            if (!iArkSparkModel.IsSelectable)
            {
                base.OnSelected(e);
                return;
            }


            if (iArkSparkModel.UseWYSIWYGEditor)
            {
                SetCorrectionTemplate(iArkSparkModel);
                SendMessage(iArkSparkModel, editor);
                base.OnSelected(e);
            }
            else
            {
                editor.MessageBus
                      .OnNext(new NewSelectionEventArgs
                       {
                           EditingItem     = (DocumentElementPresenter)iArkSparkModel,
                           WYSIWYGEditMode = true,
                       });
                base.OnSelected(e);
            }
        }

        protected override void OnUnselected(RoutedEventArgs e)
        {
            if (DataContext is not IArkSparkModel iArkSparkModel)
            {
                base.OnUnselected(e);
                return;
            }


            if (iArkSparkModel.IsSelectable)
            {
                SetCorrectionTemplate(iArkSparkModel);
            }


            InvalidateVisual();
            base.OnUnselected(e);
        }

        private void SetCorrectionTemplate(IArkSparkModel iArkSparkModel)
        {
            var editor    = TextEditor;
            var resources = IsSelected ? editor.EditingResources : editor.Resources;
            var type      = iArkSparkModel.GetType();

            if (resources is null)
            {
                return;
            }

            ContentTemplate = resources[new DataTemplateKey(type)] as DataTemplate;
        }


        internal DocumentEditor TextEditor
        {
            get
            {
                DocumentEditor editor;

                if (_asTextEditorReference is null)
                {
                    editor                 = Xaml.GetParent<DocumentEditor>(this);
                    _asTextEditorReference = new WeakReference<DocumentEditor>(editor);
                }

                if (!_asTextEditorReference.TryGetTarget(out editor))
                {
                    editor = Xaml.GetParent<DocumentEditor>(this);
                    _asTextEditorReference.SetTarget(editor);
                }

                return editor;
            }
        }



        public bool IsSelectable
        {
            get => (bool)GetValue(IsSelectableProperty);
            set => SetValue(IsSelectableProperty, Boxing.Box(value));
        }

    }
}